#pragma once

#include <Qstring>
#include <QIcon>
#include <QUuid>
#include <QDateTime>
#include <QFile>
#include <QDebug>
#include <QFileInfo>
#include "base.qpb.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "friend.qpb.h"
#include "file.qpb.h"
#include "notify.qpb.h"
#include "speech_recognition.qpb.h"
#include "message_transmit.qpb.h"
#include "message_storage.qpb.h"

//创建命名空间
namespace model
{

//////////////////////////////////////////////////////////////
/// 工具函数，供多个模块使用
/////////////////////////////////////////////////////////////
//函数定义如果写在 .h中必须加static 或者 inline(inline被编译器默认是static inline), 文件是分离编译，不加static在链接时候会报重定义错误

//获取文件名
static inline QString getFileName(const QString& path)
{
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}
//封装"宏" 作为打印日志的方法
#define TAG  QString("[%1:%2]").arg(model::getFileName(__FILE__),QString::number(__LINE__))

//不带双引号
#define LOG() qDebug().noquote() << TAG
//#define TAG "[" << __LINE__ << "]"


//格式化时间
static inline QString formatTime(int64_t timestamp)
{
   //先把时间戳转换为QDateTime 对象
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
   //把QDateTime对象转换为 "格式化时间"
    return dateTime.toString("MM-dd HH:mm:ss");
}

//通过函数得到 秒级时间
static inline int64_t getTime()
{
    // 获得时间戳
    return QDateTime::currentSecsSinceEpoch();
}

//根据QByteArraay, 转换成QIcon
static inline QIcon makeIcon(const QByteArray& byteArray)
{
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon (pixmap);
    return icon;
}

//读写文件
//从指定文件中，读取所有二进制内容,得到一个 QByteArray
static inline QByteArray loadFileToByteArray(const QString & path)
{
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if (!ok)
    {
        qDebug() << "文件打开失败" ;
        return QByteArray();
    }

    QByteArray content = file.readAll();
    file.close();
    return content;
}

//把QByteArray 中的内容,写入到某个指定文件里
static inline void writeByteArrayToFile(const QString& path,  const QByteArray& content)
{
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);

    if (!ok)
    {
        qDebug() << "文件打开失败";
        return;
    }

    file.write(content);
    file.flush();
    file.close();
}

//////////////////////////////////////////////////////////////
/// 用户信息
/////////////////////////////////////////////////////////////

class UserInfo
{
public:
    QString userId = " ";                       //用户编号
    QString nickname = "";                      //用户昵称
    QString description = " ";                  //用户签名
    QString phone = " ";                        //用户手机号码
    QIcon   avatar;                             //用户头像

    //从 protobuffer 的 UserInfo对象,转换成代码的 UserInfo对象
    void load(const shiyue_im::UserInfo& userInfo)
    {
        this->userId      = userInfo.userId();
        this->nickname    = userInfo.nickname();
        this->phone       = userInfo.phone();
        this->description = userInfo.description();
        if (userInfo.avatar().isEmpty())
        {
            // 使用默认头像
            this->avatar  = QIcon(":/resource/image/defaultAvatar.png");
        }
        else
        {
            this->avatar  = makeIcon(userInfo.avatar());
        }
    }
};

//////////////////////////////////////////////////////////////
/// 消息信息
/////////////////////////////////////////////////////////////

enum MessageType
{
    TEXT_TYPE,             //文本消息
    IMAGE_TYPE,            //图片消息
    FILE_TYPE,             //文件消息
    SPEECH_TYPE            //语言消息
};

class Message
{
public:
    QString messageId = " ";                             //消息编号
    QString chatSessionId = " ";                         //消息所属会话的编号
    QString time = " ";                                  //消息的时间。通过格式化的时间方式来表示，形如 06-07 12：00：00
    MessageType messageType;                             //消息类型
    UserInfo sender;                                     //发送者的信息
    QByteArray content;                                  //消息的正文内容
    QString fileId = " ";                                //文件身份标识当消息类型为文件，图片，语言才有效，为文本时为空;
    QString fileName = " ";                              //文件名称当消息类型为文件时才有用，其余为空字符串；

//工厂模式构造message对象

    static Message makeMessage(MessageType messageType, const QString& chatSessionId,  const UserInfo& sender, const QByteArray& content, const QString & extraInfo)
    {
        if (messageType == TEXT_TYPE)
        {
            return makeTextMessage(chatSessionId, sender, content);
        }
        else if(messageType == IMAGE_TYPE)
        {
            return makeImageMessage(chatSessionId, sender, content);
        }
        else if (messageType == FILE_TYPE)
        {
            return makeFileMessage(chatSessionId, sender, content, extraInfo);
        }
        else if (messageType == SPEECH_TYPE)
        {
            return makeSpeechMessage(chatSessionId, sender, content);
        }
        else
        {
            return Message();
        }
    }

    void load(const shiyue_im::MessageInfo& messageInfo)
    {
        this->messageId = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time      =  formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());


        // 设置消息类型
        auto type = messageInfo.message().messageType();
        if (type == shiyue_im::MessageTypeGadget::MessageType::STRING)
        {
            this->messageType = TEXT_TYPE;


            this->content    = messageInfo.message().stringMessage().content().toUtf8();

        }
        else if (type == shiyue_im::MessageTypeGadget::MessageType::IMAGE)
        {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent())
            {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId())
            {
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        }
        else if (type == shiyue_im::MessageTypeGadget::MessageType::FILE)
        {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents())
            {
                this->content = messageInfo.message().fileMessage().fileContents();
            }

            if (messageInfo.message().fileMessage().hasFileId())
            {
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();

        }
        else if (type == shiyue_im::MessageTypeGadget::MessageType::SPEECH)
        {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents())
            {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId())
            {
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        }
        else
        {
            // 错误的类型,打印日志
            LOG() << "非法消息类型! type = " << type;
        }


    }
private:

    //通过此方法生成唯一的messageId
    static QString makeId()
    {
        return "M" + QUuid::createUuid().toString().sliced(25,12);
    }

    static Message makeTextMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray &content)
    {
        Message message;

        //此处需要确保,设置的,messageId是唯一的
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender    = sender;

        //生成一个格式化的时间
        message.time =  formatTime(getTime());
        message.content = content;
        message.messageType = TEXT_TYPE;

        //对于文本消息而言,以下两个属性不使用,设为"  "
        message.fileId = " ";
        message.fileName = " ";
        return message;
    }

    static Message makeImageMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray &content)
    {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender   = sender;
        message.time = formatTime(getTime());
        message.content =  content;
        message.messageType = IMAGE_TYPE;
        //fileId 后续使用的时候再进一步设置
        message.fileId = " ";
        //filename 不使用,直接设为“ ”
        message.fileName = " ";
        return message;
    }
    static Message makeFileMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray &content, const QString& fileName)
  {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.messageType = FILE_TYPE;
        //fileId 后续使用的时候再进一步设置
        message.fileId = " ";
        message.fileName = fileName;
        return message;
    }
    static Message makeSpeechMessage(const QString& chatSessionId, const UserInfo& sender, const QByteArray &content)
    {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.content = content;
        message.messageType = SPEECH_TYPE;
        //fileid 后续使用时设置
        message.fileId = " ";
        //fileName不使用直接设置为" "
        message.fileName = " ";
        return message;
    }


};

//////////////////////////////////////////////////////////////
/// 会话信息
/////////////////////////////////////////////////////////////

class ChatSessionInfo
{

public:
    QString chatSessionId = " ";                       //会话ID
    QString chatSessionName = " ";                     //会话名字,如果会话是单聊显示对方名称,群聊显示群聊名称;
    Message lastMessage;                               //表示最新的消息
    QIcon       avatar;                                //会话头像如果是单聊显示对方头像，如果是群聊显示群聊头像
    QString   userId = " ";                            //如果会话是单聊显示对方id,如果是群聊，先设置空，后续其他方式设置完整用户ID列表

    void load(const shiyue_im::ChatSessionInfo& chatSessionInfo)
    {
        this->chatSessionId = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();

        if (chatSessionInfo.hasSingleChatFriendId())
        {
            this->userId = chatSessionInfo.singleChatFriendId();

        }
        if (chatSessionInfo.hasPrevMessage())
        {
            lastMessage.load(chatSessionInfo.prevMessage());

        }
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty())
        {
            this->avatar = makeIcon(chatSessionInfo.avatar());

        }
        else
        {
            //如果没有头像,根据当前会话是单聊还是群聊,使用不同的默认头像
            if (userId != "")
            {
                //单聊
                this->avatar = QIcon(":/resource/image/defaultAvatar.png");
            }
            else
            {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }

    }
};

} //model end
